package com.hmall.gateway.routers;

import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

// 动态路由
@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {
    private final NacosConfigManager nacosConfigManager;
    private static final String dataId = "gateway-routers.json";
    private static final String group = "DEFAULT_GROUP";

    private final RouteDefinitionWriter writer;
    private final Set<String> routeIds = new HashSet<>();
    @PostConstruct
    public void initRouterConfigListener() throws NacosException {
        String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {
            @Override
            public Executor getExecutor() {
                return null;
            }
            @Override
            public void receiveConfigInfo(String configInfo) {
                // 监听后做的事情
                updateRouterConfig(configInfo);

            }
        });
        // 3. 第一次读取配置，也需要进行更新路由表
        updateRouterConfig(configInfo);
    }


    // 4. 更新路由表
    public void updateRouterConfig(String configInfo)  {
        log.info("更新路由表为："+ configInfo);
      // 4.1. 解析路由表
        List<RouteDefinition> list = JSONUtil.toList(configInfo, RouteDefinition.class);
        // 4.2. 删除旧的路由表，如果第一次因为为空，不可能进行for循环的
        for (String id : routeIds) {
            writer.delete(Mono.just(id)).subscribe();
        }
        routeIds.clear();
        // 4.3. 添加新路由表
        for (RouteDefinition l : list) {// 订阅路由配置变化
            writer.save(Mono.just(l)).subscribe();
            // 记录本次的id，方便下一次更新删除旧的数据
            routeIds.add(l.getId());
        }
    }
}
